
import UIKit
import CommonCrypto


let isIphoneX: Bool = {
    return screenHeight >= 812
}()
let NavHeight: CGFloat = {
    return isIphoneX ? 88 : 64
}()
let StatusBarHeight: CGFloat = {
    return isIphoneX ? 44 : 20
}()
let TabbarSafeBottomMargin: CGFloat = {
    return isIphoneX ? 34: 0
}()
let TabbarHeight: CGFloat = {
    return isIphoneX ? 83: 49
}()
let screenWidth: CGFloat = {
    return UIScreen.main.bounds.size.width
}()
let screenHeight: CGFloat = {
    return UIScreen.main.bounds.size.height
}()


//MARK: - CACornerMask
extension CACornerMask {
    static let allCorner: CACornerMask = {
        return [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMinYCorner, .layerMaxXMaxYCorner]
    }()
}

//MARK: - Double
extension Double {
    /// 适配屏幕宽
    var Fit: CGFloat {
        return CGFloat(self) * screenWidth / 375.0
    }
    /// 适配屏幕高
    var FitH: CGFloat {
        return CGFloat(self) * screenHeight / 812.0
    }
}

//MARK: - UIImage
extension UIImage {
    /// 颜色转图片
    /// - Parameter color: 颜色
    /// - Returns: 转换后的图片
    static func colorToImage(color: UIColor) -> UIImage {
        let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
        UIGraphicsBeginImageContext(rect.size)
        let context = UIGraphicsGetCurrentContext()
        context?.setFillColor(color.cgColor)
        context?.fill(rect)
        let theImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return theImage!
    }
}

//MARK: - 视图渐变色(https://github.com/ChaselAn/ACShadeView)
extension UIView {
    
    // 渐变的方向
    public enum ACShadeDirectionDIr: String {
        case topToBottom = "0001"
        case leftToRight = "0010"
        case bottomToTop = "0100"
        case rightToLeft = "1000"
        case leftTopToRightBottom = "0011"
        case rightTopToLeftBottom = "1001"
        case leftBottomToRightTop = "0110"
        case rightBottomToLeftTop = "1100"
    }

    /// 根据一个颜色的透明度渐变,默认方向从上到下
    ///
    /// - parameter color:     渐变的颜色
    /// - parameter fromAlpha: 从什么透明度开始
    /// - parameter toAlpha:   到什么透明度结束
    /// - parameter direction: 渐变的方向
    public func ac_shadeView(withColor color: UIColor, fromAlpha: CGFloat = 0, toAlpha: CGFloat = 1, direction: ACShadeDirectionDIr = .topToBottom) {
        var fromAlpha = fromAlpha
        fromAlpha = max(0, fromAlpha)
        var toAlpha = toAlpha
        toAlpha = min(1, toAlpha)
        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [color.withAlphaComponent(fromAlpha).cgColor,color.withAlphaComponent(toAlpha).cgColor]
        self.layoutIfNeeded()
        gradientLayer.frame = CGRect(x: 0, y: 0, width: self.bounds.width, height: self.bounds.height)
        ac_startAndEndPoint(gradientLayer, direction: direction)
        self.layer.addSublayer(gradientLayer)
    }
    
    /// 根据一个16进制颜色的透明度渐变,默认方向从上到下
    ///
    /// - parameter RGBcolor:  6位或者8位的16进制颜色字符串
    /// - parameter fromAlpha: 从什么透明度开始
    /// - parameter ToAlpha:   到什么透明度结束
    /// - parameter direction: 渐变的方向
    public func ac_shadeView(WithRGBcolor color: String, fromAlpha: CGFloat = 0, toAlpha: CGFloat = 1, direction: ACShadeDirectionDIr = .topToBottom) {
        ac_shadeView(withColor: .color(hexString: color), fromAlpha: fromAlpha, toAlpha: toAlpha, direction: direction)
    }
    
    /// 多个颜色的渐变，默认方向从上到下
    ///
    /// - parameter colorList: 颜色的数组
    /// - parameter direction: 渐变的方向
    public func ac_shadeView(withColorList colorList: [UIColor], direction: ACShadeDirectionDIr = .topToBottom) {
        let gradientLayer = CAGradientLayer()
        let list = colorList.map({$0.cgColor})
        gradientLayer.colors = list
        self.layoutIfNeeded()
        gradientLayer.frame = CGRect(x: 0, y: 0, width: self.bounds.width, height: self.bounds.height)
        ac_startAndEndPoint(gradientLayer, direction: direction)
        self.layer.addSublayer(gradientLayer)
    }
    
    
    /// 多个16进制字符串颜色的渐变，默认方向从上到下
    ///
    /// - parameter colorList: 16进制字符串颜色的数组
    /// - parameter direction: 渐变的方向
    public func ac_shadeView(withRGBcolorList RGBcolorList: [String], direction: ACShadeDirectionDIr = .topToBottom) {
        ac_shadeView(withColorList: RGBcolorList.map({ .color(hexString: $0) }), direction: direction)
    }
    
    // 根据方向计算起点与终点
    private func ac_startAndEndPoint(_ gradientLayer: CAGradientLayer,direction: ACShadeDirectionDIr) {
        let str = direction.rawValue
        gradientLayer.startPoint = CGPoint(x: Int(str[str.index(str.startIndex, offsetBy: 0)..<str.index(str.endIndex, offsetBy: -3)]) ?? 0, y: Int(str[str.index(str.startIndex, offsetBy: 1)..<str.index(str.endIndex, offsetBy: -2)]) ?? 0)
        gradientLayer.endPoint = CGPoint(x: Int(str[str.index(str.startIndex, offsetBy: 2)..<str.index(str.endIndex, offsetBy: -1)]) ?? 0, y: Int(str[str.index(str.endIndex, offsetBy: -1)..<str.index(str.endIndex, offsetBy: 0)]) ?? 0)
    }
    
}

extension UIColor{
    
    /// 通过16进制字符串得到颜色
    public class func color(hexString: String, alpha: CGFloat = 1.0) -> UIColor {
        var cString : String = hexString.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
        // String should be 6 or 8 characters
        
        if cString.count < 6 {
            return UIColor.black
        }
        
        if cString.hasPrefix("0X"){
            cString = NSString(string: cString).substring(from: 2)
        }
        if cString.hasPrefix("#"){
            cString = NSString(string: cString).substring(from: 1)
        }
        if cString.count != 6{
            return UIColor.black
        }
        // Separate into r, g, b substrings
        var range  = NSRange(location: 0,length: 2)
        let rString = NSString(string: cString).substring(with: range)
        range.location = 2
        let gString = NSString(string: cString).substring(with: range)
        range.location = 4
        let bString = NSString(string: cString).substring(with: range)
        
        // Scan values
        var r, g, b : UInt32?
        r = 0
        g = 0
        b = 0
        Scanner(string: rString).scanHexInt32(&r!)
        Scanner(string: gString).scanHexInt32(&g!)
        Scanner(string: bString).scanHexInt32(&b!)
        
        return UIColor(red: (CGFloat(r!))/255.0, green: (CGFloat(g!))/255.0, blue: (CGFloat(b!))/255.0, alpha: alpha)
    }
    
    static func blackComponent(_ alpha: CGFloat) -> UIColor {
        return UIColor.black.withAlphaComponent(alpha)
    }

}



//MARK: - UILabel
extension UILabel {
    
    /// 添加图片
    /// - Parameter image: 图片
    /// - Parameter rect: 图片
    func attachment(_ image: UIImage?, _ rect: CGRect, _ isFirst: Bool = true) {
        guard let img = image else {return}
        let attributeString = NSMutableAttributedString()
        let attachMent = NSTextAttachment()
        attachMent.image = img
        attachMent.bounds = rect
        if isFirst {
            let imgAttr = NSAttributedString(attachment: attachMent)
            attributeString.append(imgAttr)
            let textArt = NSAttributedString(string: " " + (self.text ?? ""))
            attributeString.append(textArt)
        }else {
            let textArt = NSAttributedString(string: (self.text ?? "") + " " )
            attributeString.append(textArt)
            let imgAttr = NSAttributedString(attachment: attachMent)
            attributeString.append(imgAttr)
        }
        self.attributedText = attributeString
    }
    
    func setShadowText(_ color: UIColor = UIColor.blackComponent(0.4)) {
        guard let text = self.text else { return }
        let shadow = NSShadow()
        shadow.shadowBlurRadius = 1
        shadow.shadowOffset = CGSize(width: 1, height: 1)
        shadow.shadowColor = color
        let attributeString = NSMutableAttributedString(string: text, attributes: [.shadow: shadow])
        self.attributedText = attributeString
    }
    
}


//MARK: - Dictionary
extension Dictionary {
    
    var toJsonString: String {
        guard let data = try? JSONSerialization.data(withJSONObject: self, options: []) else { return "" }
        guard let str = String(data: data, encoding: .utf8) else { return "" }
        return str
    }
    
}



//MARK: - String
extension String {
    
    /// 随机长度字符串
    /// - Parameter length: 长度
    /// - Returns: 描述
    static func randomString(length: Int) -> String {
        let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
        let len = UInt32(letters.length)
        var randomString = ""
        for _ in 0 ..< length {
            let rand = arc4random_uniform(len)
            var nextChar = letters.character(at: Int(rand))
            randomString += NSString(characters: &nextChar, length: 1) as String
        }
        return randomString
    }
    
    /// 按长度从左至右截取字符串
    /// - Parameter count: 需要截取的长度
    func subStringToShort(_ count: Int = 13) -> String {
        return self.count > count ? (String(self.prefix(count)) + "...") : self
    }
    
    /// 计算文本宽度
    /// - Parameters:
    ///   - size: 期望size
    ///   - font: 字体
    /// - Returns: 文本宽度
    func caculateWidth(_ size: CGSize!,_ font: UIFont) -> CGFloat {
        var rect: CGRect = .zero
        DispatchQueue.global().sync {
            rect = NSString(string: self).boundingRect(with: size, options: NSStringDrawingOptions(rawValue: NSStringDrawingOptions.usesLineFragmentOrigin.rawValue | NSStringDrawingOptions.usesFontLeading.rawValue | NSStringDrawingOptions.usesDeviceMetrics.rawValue | NSStringDrawingOptions.truncatesLastVisibleLine.rawValue), attributes: [NSAttributedString.Key.font: font], context: nil)
        }
        return rect.size.width
    }
    
    /// 计算文本高度
    /// - Parameters:
    ///   - size: 期望size
    ///   - font: 字体
    /// - Returns: 文本高度
    func caculateHeight(_ size: CGSize!,_ font: UIFont) -> CGFloat {
        let rect = NSString(string: self).boundingRect(with: size, options: NSStringDrawingOptions(rawValue: NSStringDrawingOptions.usesLineFragmentOrigin.rawValue | NSStringDrawingOptions.usesFontLeading.rawValue | NSStringDrawingOptions.usesDeviceMetrics.rawValue | NSStringDrawingOptions.truncatesLastVisibleLine.rawValue), attributes: [NSAttributedString.Key.font: font], context: nil)
        return rect.size.height
    }
    
    var toYear: String {
        if self == "0001-01-01" {
            return ""
        }
        let format = DateFormatter()
        format.dateFormat = "yyyy-MM-dd"
        if let oldDate = format.date(from: self) {
            let currentDate = Date()
            let timeInterval = currentDate.timeIntervalSince(oldDate)
            let time = timeInterval/(3600*24*365)
            return ", \(Int(time))"
        }
        return ""
    }
    
    var intValue: Int {
        return (self as NSString).integerValue
    }
    
    /// 字符串转URL（包含判断URL的有效性）
    var toURL: URL? {
        let preticate = "((http[s]{0,1}|ftp)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)"
        let urlPredicateTest = NSPredicate(format: "SELF MATCHES %@", preticate)
        guard urlPredicateTest.evaluate(with: self) else { return nil }
        return URL(string: self)
    }
    
    /// 邮箱格式验证
    var toEmail: Bool {
        guard self.count > 0 else { return false }
        let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"
        let emailTest:NSPredicate = NSPredicate(format: "SELF MATCHES %@", emailRegex)
        return emailTest.evaluate(with: self)
    }
    
    var isFormatNumber: Bool {
        return allSatisfy({$0.isNumber})
    }
    
    
    var containsUrl: [String] {
        var urls: [String] = []
        do {
            let dataDetector = try NSDataDetector(types: NSTextCheckingTypes(NSTextCheckingResult.CheckingType.link.rawValue))
            let res = dataDetector.matches(in: self, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSRange(location: 0, length: self.count))
            for item in res {
                urls.append((self as NSString).substring(with: item.range))
            }
        } catch {
            print(error)
        }
        return urls
    }
    
    var isNewLine: Bool {
        return allSatisfy({$0.isNewline})
    }
    
    var isBlank : Bool {
        return allSatisfy({$0.isWhitespace})
    }
    
    var whitespaceFormat: String {
        return self.trimmingCharacters(in: .whitespacesAndNewlines)
    }
    
    func convertDictionary() -> NSDictionary? {
        let string = (self as NSString).trimmingCharacters(in: CharacterSet.controlCharacters)
        guard let jsonData: Data = string.data(using: .utf8) else { return nil }
        if let dict = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) {
            return dict as? NSDictionary
        }
        return nil
    }
    
}

extension Optional where Wrapped == String {
    var isBlank : Bool{
        return self?.isBlank ?? true
    }
}

//MARK: - Array
extension Set where Element: Equatable {
    
    func containsArray(array: [Element]) -> Bool {
        return !array.contains { !self.contains($0) }
    }
    
}

extension Array where Element: Equatable {
    
    func containsArray(array: [Element]) -> Bool {
        return !array.contains { !self.contains($0) }
    }
    
}

extension UIFont {
    
    enum FontType {
        case bold, medium, extraBold,system,thin
        var fontName: UIFont.Weight {
            switch self {
            case .extraBold:
                return UIFont.Weight.black
            case .bold:
                return UIFont.Weight.bold
            case .medium:
                return UIFont.Weight.semibold
            case .system:
                return UIFont.Weight.regular
            case .thin:
                return UIFont.Weight.thin
            }
        }
    }
    
    static func setTypeFace(_ size: CGFloat!, type: FontType = .bold) -> UIFont {
         return UIFont.systemFont(ofSize: size, weight: type.fontName)
    }


}

//MARK: - Mirror
extension Mirror {
    
    static func valid(obj: Any) -> Mirror.DisplayStyle {
        return Mirror(reflecting: obj).displayStyle ?? .class
    }
    
}


//MARK: - DispatchQueue
extension DispatchQueue {
    private static var _onceToken = [String]()
    
    class func once(token: String = "\(#file):\(#function):\(#line)", block: ()->Void) {
        objc_sync_enter(self)
        
        defer {
            objc_sync_exit(self)
        }

        if _onceToken.contains(token) {
            return
        }

        _onceToken.append(token)
        block()
    }
}
